/*
 * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
 * http://www.gnu.org/licenses/gpl-3.0.html
 *
 * $Revision: 7107 $
 * $Id: main.cpp 7107 2011-04-15 11:19:11Z mortenmacfly $
 * $HeadURL: http://svn.code.sf.net/p/codeblocks/code/branches/release-17.xx/src/tools/ConsoleRunner/main.cpp $
 */
/*
 * 控制台运行器
 * */
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#ifdef __WXMSW__
    #include <windows.h>
    #include <conio.h>
    #define wait_key getch
#else
    #define wait_key getchar
#endif
#if defined(__unix__) || defined(__unix)
    #include <sys/wait.h>
#endif
#include <string.h>

#ifdef __MINGW32__
int _CRT_glob = 0;
#endif

bool hasSpaces(const char* str)
{
    char last = 0;
    while (str && *str)
    {
        if ((*str == ' ' || *str == '\t') && last != '\\')
            return true;
        last = *str++;
    }
    return false;
}

int execute_command(char *cmdline){
//windows平台
#ifdef __WXMSW__
    //Windows's system() seems to not be able to handle parentheses in
    //the path, so we have to launch the program a different way.
    //Windows的system()似乎无法处理路径中的括号,因此我们必须以不同的方式启动程序.

    SetConsoleTitle(cmdline);

    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    // Start the child process.
    //启动子进程
    CreateProcess( NULL, TEXT(cmdline), NULL, NULL, FALSE, 0,NULL, NULL, &si, &pi );

    // Wait until child process exits.
    //等待直到子进程退出
    WaitForSingleObject( pi.hProcess, INFINITE );

    // Get the return value of the child process
    //获取子进程的返回值
    DWORD ret;
    GetExitCodeProcess( pi.hProcess, &ret );

    // Close process and thread handles.
    // 关闭进程和线程句柄
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );

    return ret;
#else
    //system()函数以shell命令的形式执行给定的行.此函数是一个取消点,因此没有用'__THROW'标记.
    int ret = system(cmdline);

    if(WIFEXITED(ret)){return WEXITSTATUS(ret);}else{return -1;}
#endif
}

int main(int argc, char** argv)
{
    if (argc < 2)
    {
        printf("使用方式: cb_console_runner <文件名> <参数 ...>\n");
        return 1;
    }

    // count size of arguments
    //参数的计数大小
    size_t fullsize = 0;
    for (int i = 1; i < argc; ++i)
    {
        fullsize += strlen(argv[i]);
    }
    // add some slack for spaces between args plus quotes around executable
    // 在可执行文件的参数和引号之间添加一些空格
    fullsize += argc + 32;

    char* cmdline = new char[fullsize];
    memset(cmdline, 0, fullsize);

    // 1st arg (executable) enclosed in quotes to support filenames with spaces
    // 第一个参数(可执行文件)用引号括起来,以支持带空格的文件名
    bool sp = hasSpaces(argv[1]);
    if (sp){ strcat(cmdline, "\"");}
    strcat(cmdline, argv[1]);
    if (sp){strcat(cmdline, "\"");}
    strcat(cmdline, " ");

    for (int i = 2; i < argc; ++i)
    {
        sp = hasSpaces(argv[i]);
        if (sp){strcat(cmdline, "\"");}
        strcat(cmdline, argv[i]);
        if (sp){strcat(cmdline, "\"");}
        strcat(cmdline, " ");
    }

    timeval tv;
    gettimeofday(&tv, NULL);
    //秒数
    double cl = tv.tv_sec + (double)tv.tv_usec / 1000000;

    int ret = execute_command(cmdline);

    gettimeofday(&tv, NULL);
    cl = (tv.tv_sec + (double)tv.tv_usec / 1000000) - cl;

    printf("\n进程返回 %d (0x%X)   执行时间 : %0.3f s", ret, ret, cl);
    #ifdef __WXMSW__
    printf("\n按下任何键继续.\n");
    #else
    printf("\n按下回车键继续.\n");
    #endif

    wait_key();

    delete[] cmdline;
    return ret;
}
